using Microsoft.Extensions.DependencyInjection;
using Vin.Tool.AspNetCore.Factory;

namespace Vin.Tool.AspNetCore.Extension;

public static class KeyedExtension
{
    public static VinKeyedServiceFactory VinKeyedServiceFactory = new();

    // TODO：使用工厂模式，后续替换为AOP
    public static bool UseFactory => true;

    #region 注册服务

    public static IServiceCollection AddKeyedScoped(this IServiceCollection serviceCollection, Type serviceType,
        string? key, Type implementationType)
    {
        if (UseFactory)
        {
            VinKeyedServiceFactory.AddKeyedService(key, serviceType, implementationType);
        }
        else
        {
            serviceCollection.AddKeyedScoped(serviceType, key, implementationType);
        }

        return serviceCollection;
    }

    public static IServiceCollection AddKeyedSingleton(this IServiceCollection serviceCollection, Type serviceType,
        string? key, Type implementationType)
    {
        if (UseFactory)
        {
            VinKeyedServiceFactory.AddKeyedService(key, serviceType, implementationType);
        }
        else
        {
            serviceCollection.AddKeyedSingleton(serviceType, key, implementationType);
        }

        return serviceCollection;
    }

    public static IServiceCollection AddKeyedTransient(this IServiceCollection serviceCollection, Type serviceType,
        string? key, Type implementationType)
    {
        if (UseFactory)
        {
            VinKeyedServiceFactory.AddKeyedService(key, serviceType, implementationType);
        }
        else
        {
            serviceCollection.AddKeyedTransient(serviceType, key, implementationType);
        }

        return serviceCollection;
    }

    #endregion

    #region 获取服务

    public static object? GetKeyedService(this IServiceProvider serviceProvider, string? key, Type implementationType)
    {
        if (UseFactory)
        {
            return VinKeyedServiceFactory.GetKeyedService(serviceProvider, key, implementationType);
        }

        return serviceProvider.GetKeyedService(key, implementationType);
    }

    public static T? GetKeyedService<T>(this IServiceProvider serviceProvider, string? key)
    {
        return (T?)GetKeyedService(serviceProvider, key, typeof(T));
    }

    public static object GetRequiredKeyedService(this IServiceProvider serviceProvider, Type implementationType,
        string? key)
    {
        return GetKeyedService(serviceProvider, key, implementationType) ??
               throw new InvalidOperationException("Keyed service not found");
    }

    public static T GetRequiredKeyedService<T>(this IServiceProvider serviceProvider, string? key)
    {
        return (T)GetKeyedService(serviceProvider, key, typeof(T))!;
    }

    public static IEnumerable<object?> GetKeyedServices(this IServiceProvider serviceProvider, Type implementationType,
        string? key)
    {
        if (UseFactory)
        {
            return VinKeyedServiceFactory.GetKeyedServices(serviceProvider, key, implementationType);
        }

        return serviceProvider.GetKeyedServices(implementationType, key);
    }

    #endregion
}